#include <cstdio>
#include <cstdlib>
#include <math.h>
#include "vectclasses.hpp"      // Contains information about the Vector and VectorArray classes.
#include "classifyclasses.hpp"  // Contains functions necessary for classification (when the kernel vectors are already given or computed).
#include "learnclasses.hpp"     // Contains functions for teaching the neural network.
#include "drawclasses.hpp"      // Contains functions for drawing digits.
#include "inputclasses.hpp"     // Contains functions for reading the data.
#include "outputclasses.hpp"    // Contains functions for outputting the results.


int main(int argc, char ** argv)
{
    int teacher = -1;       // If teacher=0, then we must supply the kernel vectors. If teacher=1, then the kernel vectors will be obtained automatically.
    VectorArray * kernel;
    VectorArray * inputvect;
    char * filename;
    char *fnamenews;

	StepChangeLawLinear alpha(0.2, 0.1);    // The parameters in the learning method change either linearly or exponentially.
	StepChangeLawLinear step(0.7, -0.1);
	LearningMethodCCM CCM(step, alpha);     // Convex Combination Method for teaching the neural network (with two parameters).
    LearningMethodSimple Simple(step);      // General method (just one parameter).
    // The parameters and learning method should be adjusted by trial and error for each individual problem.

    switch (argv[1][1])
    {
        case 'd' :              // If the user chose the "Digits" options, read the digits from the special file.
        {
            Input::ReadDigits(inputvect, kernel);
            if (argv[2][2] == 't')
            {
                teacher = 1;
            }
            else
            {
                teacher = 0;        // If the "teacher" option if off, generate the kernel - averaged digits.
                Input::DigitClasses(kernel);
            }
            break;
        }
        case 'w' :
        case 'g' :
        {
            filename = argv[2];      // If the user chose "General" or "Words", read the input from the given file.
            Input::ReadGeneral(filename, inputvect, kernel, &teacher);
            break;
        }
    }

    int vectnum = inputvect->getVectNumber();
    int classnum = kernel->getVectNumber();

    for (int i = 0; i < vectnum; i++)
    {
        (inputvect->getVector(i)).normalize();      // Normalize the input vectors.
    }

	if (1 == teacher)
	{
		CCM.learn(*inputvect, *kernel);         // The actual teaching of the network; if you want another learning method, change it here ("Simple" instead of "CCM").
	}

	Vector classresult = Classify::classifyAll(*inputvect, *kernel);        // CLassresult[i] = the number of the class to which vector number i belongs.

    switch (argv[1][1])
    {
        case 'd' :
        {
            Output::PrintGeneral(classresult);                      // Outputs which vector belongs to which class (after the classification).
            Output::PrintDigits(inputvect, kernel, teacher);        // Outputs the statistics of the classification.
            break;
        }
        case 'w' :
        {
            fnamenews = argv[3];                                    // fnamenews is the name of the original file with texts to be classified.
            Output::PrintGeneral(classresult);
            Output::PrintTexts(classresult, classnum, fnamenews);   // Generates files (one for each class) containing the texts belonging to that class.
            break;
        }
        case 'g' :
        {
            Output::PrintGeneral(classnum);
        }
    }

	return 0;
}




